﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace TimeTravel.XnaLibrary.UI
{
	/// <summary>
	/// Represents a canvas control used for hosting child elements.
	/// </summary>
	public class Canvas : Control, IPanel
	{
		private Dictionary<string, Control> mChildren;
		private Dictionary<string, Point> mRelativeChildrenLocations;

		/// <summary>
		/// Gets or sets a value indicating if this canvas should raise events.
		/// </summary>
		public override bool IsEnabled
		{
			get
			{
				return base.IsEnabled;
			}
			set
			{
				base.IsEnabled = value;
				foreach (var control in mChildren.Values)
				{
					control.IsEnabled = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets a value indicating if this canvas should be drawn.
		/// </summary>
		public override bool IsVisible
		{
			get
			{
				return base.IsVisible;
			}
			set
			{
				base.IsVisible = value;
				foreach (var control in mChildren.Values)
				{
					control.IsVisible = value;
				}
			}
		}

		/// <summary>
		/// Initializes a new Canvas instance.
		/// </summary>
		public Canvas()
		{
			mChildren = new Dictionary<string, Control>();
			mRelativeChildrenLocations = new Dictionary<string,Point>();
		}

		/// <summary>
		/// Adds a control to the canvas with the specified position relative to the canvas` position.
		/// </summary>
		/// <param name="control">The control to add.</param>
		/// <param name="relativePosition">The control`s position relative to the canvas` position</param>
		public void AddChild(Control control, Point relativePosition)
		{
			mChildren.Add(control.Name, control);
			mRelativeChildrenLocations.Add(control.Name, relativePosition);
			control.Location.Location = this.Location.Location;
			control.Location.Offset(relativePosition);
		}

		/// <summary>
		/// Adds a control to the canvas.
		/// </summary>
		/// <param name="control">The control to add.</param>
		public void AddChild(Control control)
		{
			AddChild(control, Point.Zero);
		}

		/// <summary>
		/// Removes the specified child control from the canvas.
		/// </summary>
		/// <param name="controlName">The name of the contorl to be removed.</param>
		public void RemoveChild(string controlName)
		{
			mChildren.Remove(controlName);
			mRelativeChildrenLocations.Remove(controlName);
		}

		/// <summary>
		/// Gets the child control with the specified name.
		/// </summary>
		/// <param name="controlName">THe name of the control to get.</param>
		/// <returns></returns>
		public Control GetChild(string controlName)
		{
			return mChildren[controlName];
		}

		/// <summary>
		/// Adds the specified offset to the child`s relative position.
		/// </summary>
		/// <param name="controlName">The name of the control to move.</param>
		/// <param name="offset">The offset to move the child control with.</param>
		public void MoveChild(string controlName, Point offset)
		{
			Point current = mRelativeChildrenLocations[controlName];
			current.X += offset.X;
			current.Y += offset.Y;
			mRelativeChildrenLocations[controlName] = current;
		}

		/// <summary>
		/// Updates the positions of all child controls. Call this method each time you modify the canvas` Location
		/// </summary>
		public void UpdateLocation()
		{
			foreach (var child in mChildren.Values)
			{
				child.Location.X = mRelativeChildrenLocations[child.Name].X + Location.X;
				child.Location.Y = mRelativeChildrenLocations[child.Name].Y + Location.Y;
			}
		}

		/// <summary>
		/// Checks for and raises any events that happened on the canvas or any of its child elements.
		/// </summary>
		/// <param name="currentState">The current mouse state.</param>
		/// <param name="previousState">The mouse state in the previous frame.</param>
		public override void CheckForEvents(MouseState currentState,MouseState previousState)
		{
			foreach (var namedControl in mChildren)
			{
				namedControl.Value.CheckForEvents(currentState, previousState);
			}
			base.CheckForEvents(currentState, previousState);
		}

		/// <summary> 
		/// Draws the canvas and all of its child elements with the specified SpriteBatch. SpriteBatch.Begin must have been called prior to calling this method.
		/// </summary>
		/// <param name="spriteBatch">The sprite batch to draw with.</param>
		public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
		{
			foreach (var control in mChildren.Values)
			{
				control.Draw(spriteBatch);
			}
		}
	}
}
